package com.ruoyi.web.controller.pg;

import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.pg.domain.Attachment;
import com.ruoyi.pg.domain.Indicator;
import com.ruoyi.pg.service.IAttachmentService;
import com.ruoyi.pg.service.IIndicatorService;
import com.ruoyi.system.service.ISysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 附件管理Controller
 * 
 * @author ruoyi
 * @date 2025-06-07
 */
@Slf4j
@RestController
@RequestMapping("/pg/attachment")
public class AttachmentController extends BaseController
{
    @Autowired
    private IAttachmentService attachmentService;

    @Resource
    private IIndicatorService indicatorService;

    //注入系统参数的Service
    @Resource
    private ISysConfigService configService;

    // 用于匹配文件名开头的编号，格式为数字和点号组成
    private static final Pattern CODE_PATTERN = Pattern.compile("^\\d+(?:\\.\\d+)*");


    /**
     * 查询附件管理列表
     */
    @PreAuthorize("@ss.hasPermi('pg:attachment:list')")
    @GetMapping("/list")
    public TableDataInfo list(Attachment attachment)
    {
        System.out.println("attachment.getIndicatorId ================ " + attachment.getIndicatorId());
        startPage();
        // 如果indicatorId为0，设置为null查询所有
        if (attachment.getIndicatorId() == null) {
            attachment.setIndicatorId(1L);
        }
        List<Attachment> list = attachmentService.selectAttachmentList(attachment);
        return getDataTable(list);
    }

    /**
     * 导出附件管理列表
     */
    @PreAuthorize("@ss.hasPermi('pg:attachment:export')")
    @Log(title = "附件管理", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, Attachment attachment)
    {
        List<Attachment> list = attachmentService.selectAttachmentList(attachment);
        ExcelUtil<Attachment> util = new ExcelUtil<Attachment>(Attachment.class);
        util.exportExcel(response, list, "附件管理数据");
    }

    /**
     * 获取附件管理详细信息
     */
    @PreAuthorize("@ss.hasPermi('pg:attachment:query')")
    @GetMapping(value = "/{attachId}")
    public AjaxResult getInfo(@PathVariable("attachId") Long attachId)
    {
        return success(attachmentService.selectAttachmentByAttachId(attachId));
    }

    /**
     * 获取附件管理详细信息 通过教师Id
     */
    @PreAuthorize("@ss.hasPermi('pg:attachment:query')")
    @GetMapping(value = "/getInfoByTeacherId")
    public AjaxResult getInfoByTeacherId(@RequestParam("teacherId") Long teacherId)
    {
        return success(attachmentService.selectAttachmentByTeacherId(teacherId));
    }

    /**
     * 新增附件管理
     */
    @PreAuthorize("@ss.hasPermi('pg:attachment:add')")
    @Log(title = "附件管理", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody Attachment attachment)
    {
        return toAjax(attachmentService.insertAttachment(attachment));
    }

    /**
     * 修改附件管理
     */
    @PreAuthorize("@ss.hasPermi('pg:attachment:edit')")
    @Log(title = "附件管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody Attachment attachment)
    {
        return toAjax(attachmentService.updateAttachment(attachment));
    }

    /**
     * 删除附件管理
     */
    @PreAuthorize("@ss.hasPermi('pg:attachment:remove')")
    @Log(title = "附件管理", businessType = BusinessType.DELETE)
	@DeleteMapping("/remove/{attachIds}")
    public AjaxResult remove(@PathVariable String attachIds)
    {
        List<Attachment> attachments = new ArrayList<>();

        for (String attachId : attachIds.split(",")) {
            Attachment attachment = this.attachmentService.selectAttachmentByAttachId(Long.valueOf(attachId));
            attachments.add(attachment);
        }

        Long[] arr = new Long[attachments.size()];
        for (int i = 0; i < attachments.size(); i++) {
            arr[i] = attachments.get(i).getAttachId();
        }

        // 4. 删除物理文件
        for (Attachment att : attachments) {
            if (att != null) {
                String filePath = att.getFilePath();
                System.out.println("Processing attachment: " + att.getAttachId() +
                        ", filePath: " + filePath);

                if (StringUtils.isNotBlank(filePath)) {
                    String fullPath = RuoYiConfig.getUploadPath() +"/" + filePath.replace("..", "")
                            .replace("\\", "/")
                            .replaceAll("/+", "/");

                    System.out.println("Full physical path: " + fullPath);

                    File file = new File(fullPath);
                    if (file.exists()) {
                        if (!file.delete()) {
                            log.error("文件删除失败: {}", fullPath);
                        }
                    } else {
                        log.warn("文件不存在: {}", fullPath);
                    }
                } else {
                    log.warn("附件ID {} 的filePath为空", att.getAttachId());
                }
            }
        }
        // 2. 删除数据库记录
        int deleteCount = attachmentService.deleteAttachmentByAttachIds(arr);

        return AjaxResult.success("成功删除" + deleteCount + "条记录");
    }

    /**
     * 获取指标树列表
     */
    @PreAuthorize("@ss.hasPermi('pg:attachment:list')")
    @GetMapping("/indicatorTree")
    public AjaxResult indicatorTree(Indicator indicator)
    {
        return success(this.indicatorService.selectIndicatorTreeList(indicator));
    }

    @PreAuthorize("@ss.hasPermi('pg:attachment:add')")
    @PostMapping("/upload")
    @ResponseBody
    public AjaxResult uploadFile(@RequestParam("files") MultipartFile[] files, @RequestParam(value = "indicatorId") Long indicatorId) {
        try {
            List<String> successFiles = new ArrayList<>();

            // 1. 获取完整指标点路径（从根节点开始）
            String fullIndicatorPath = getFullIndicatorPath(indicatorId);

            // 2. 构建存储路径（包含根节点"赤峰学院"）
            String storagePath = RuoYiConfig.getUploadPath() + "/" + fullIndicatorPath;

            // 3. 创建目录（如果不存在）
            File dir = new File(storagePath);
            if (!dir.exists() && !dir.mkdirs()) {
                throw new IOException("目录创建失败: " + storagePath);
            }

            // 4. 处理每个文件
            for (MultipartFile file : files) {
                if (file.isEmpty()) continue;

                String originalFilename = file.getOriginalFilename();
                String filePath = storagePath + "/" + originalFilename;

                // 保存文件
                file.transferTo(new File(filePath));

                //获取系统中的参数“pg.attach.sort.type”的值
                String sortType = this.configService.selectConfigByKey("pg.attach.sort.type");
                log.info("系统参数pg.attach.sort.type的值为：" + sortType);

                List<Attachment> list = this.attachmentService.selectAttachmentByIndicatorIdAndFileName(indicatorId,originalFilename);
                //Attachment attach = list.get(0);
                System.out.println("list ================================== " + list.size());
                if (list!=null && list.size() != 0) {
                    Attachment attach = list.get(0);
                    attach.setUpdateTime(new Date());
                    this.attachmentService.updateAttachment(attach);
                }else{//当前指标下有同名
                    // 保存到数据库，如果文件路径在数据表中已经存在，则更新记录，否则才是新增记录已经存在
                    Attachment attachment = new Attachment();
                    attachment.setFileName(originalFilename);
                    attachment.setFilePath(fullIndicatorPath + "/" + originalFilename);
                    attachment.setFileType(getFileExtension(originalFilename));
                    attachment.setFileSize(file.getSize());
                    attachment.setIndicatorId(indicatorId);
                    attachment.setCreateBy(SecurityUtils.getUsername());
                    attachment.setCreateTime(new Date());
                    if(sortType.equals("0")){//按文件编号排序
                        Matcher matcher = CODE_PATTERN.matcher(originalFilename);
                        if(matcher.find()){
                            attachment.setAttachCode(matcher.group());
                            System.out.println("matcher group= " + matcher.group());
                        }
                    }
                    System.out.println("attachment Code= " + attachment.getAttachCode());
                    this.attachmentService.insertAttachment(attachment);
                    successFiles.add(originalFilename);
                }
            }
            return AjaxResult.success("上传成功").put("successFiles", successFiles).put("count", successFiles.size());

        } catch (Exception e) {
            return AjaxResult.error("上传失败: " + e.getMessage());
        }
    }

    // 获取完整指标点路径（从根节点开始）
    private String getFullIndicatorPath(Long indicatorId) {
        List<String> pathSegments = new ArrayList<>();
        Indicator current = this.indicatorService.selectIndicatorByIndicatorId(indicatorId);

        // 向上追溯直到根节点
        while (current != null) {
            pathSegments.add(current.getIndicatorName());
            current = current.getParentId() != 0 ?
                    this.indicatorService.selectIndicatorByIndicatorId(current.getParentId()) : null;
        }

        // 反转顺序（根节点在前）
        Collections.reverse(pathSegments);
        return String.join("/", pathSegments); // 格式：赤峰学院/7.领导班子
    }

    // 纯Java实现文件名解析
    private String extractFileName(String filename) {
        return filename.contains(".") ?
                filename.substring(0, filename.lastIndexOf('.')) : filename;
    }

    private String extractFileExt(String filename) {
        return filename.contains(".") ?
                filename.substring(filename.lastIndexOf('.') + 1).toLowerCase() : "";
    }

    // 手动实现获取文件名（不含扩展名）
    private String getFileNameWithoutExt(String filename) {
        int dotIndex = filename.lastIndexOf('.');
        return (dotIndex == -1) ? filename : filename.substring(0, dotIndex);
    }

    // 手动实现获取文件扩展名
    private String getFileExtension(String filename) {
        int dotIndex = filename.lastIndexOf('.');
        return (dotIndex == -1) ? "" : filename.substring(dotIndex + 1).toLowerCase();
    }

    // 构建完整指标路径
    private String buildFullIndicatorPath(Indicator indicator) {
        List<String> pathSegments = new ArrayList<>();
        while (indicator != null) {
            pathSegments.add(indicator.getIndicatorName());
            indicator = indicator.getParentId() != 0 ?
                    this.indicatorService.selectIndicatorByIndicatorId(indicator.getParentId()) : null;
        }
        Collections.reverse(pathSegments);
        return String.join("/", pathSegments);
    }

    // 构建指标点路径
    private String buildIndicatorPath(Long indicatorId) {
        Indicator indicator = this.indicatorService.selectIndicatorByIndicatorId(indicatorId);
        if (indicator == null) {
            throw new RuntimeException("指标点不存在");
        }

        // 获取完整层级路径
        List<String> pathSegments = new ArrayList<>();
        while (indicator != null && indicator.getParentId() != 0) {
            pathSegments.add(indicator.getIndicatorName());
            indicator = this.indicatorService.selectIndicatorByIndicatorId(indicator.getParentId());
        }
        // 反转顺序（从根到当前）
        Collections.reverse(pathSegments);
        return String.join("/", pathSegments);
    }

    // 创建目录
    private void createDirectory(String path) throws IOException {
        File dir = new File(path);
        if (!dir.exists() && !dir.mkdirs()) {
            throw new IOException("目录创建失败: " + path);
        }
    }

    // 保存文件
    private void saveFile(MultipartFile file, String filePath) throws IOException {
        File dest = new File(filePath);
        file.transferTo(dest);
    }

    @PreAuthorize("@ss.hasPermi('pg:attachment:query')")
    @GetMapping("/file/preview")
    public void previewFile(
            @RequestParam Long attachId,
            HttpServletResponse response) throws IOException {

        log.info("previewFile: attachId = {}", attachId);

        // 1. 禁用缓存
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);

        // 2. 获取文件信息
        Attachment attachment = attachmentService.selectAttachmentByAttachId(attachId);

        log.info("previewFile: attachment getFilePath = {}", attachment.getFilePath());
        log.info("previewFile: RuoYiConfig.getUploadPath() = {}", RuoYiConfig.getUploadPath());

        // 确保路径拼接正确
        String fullPath = RuoYiConfig.getUploadPath() + "/" + attachment.getFilePath();
        Path filePath = Paths.get(fullPath);

        if (!Files.exists(filePath)) {
            throw new ServiceException("文件不存在");
        }

        // 3. 设置响应头
        String contentType = Files.probeContentType(filePath);
        response.setContentType(contentType != null ? contentType : "application/octet-stream");
        response.setHeader("Content-Disposition", "inline; filename=\"" +
                URLEncoder.encode(attachment.getFileName(), StandardCharsets.UTF_8.name()) + "\"");

        // 4. 使用Java原生IO流传输（完全替代IOUtils）
        try (
                InputStream in = Files.newInputStream(filePath);
                OutputStream out = response.getOutputStream()
        ) {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
            out.flush();
        }
    }
    @PreAuthorize("@ss.hasPermi('pg:attachment:query')")
    @GetMapping("/file/preview2")
    public void previewFile2(
            @RequestParam Long attachId,
            HttpServletResponse response) throws IOException {

        log.info("previewFile: attachId = {}", attachId);

        // 1. 禁用缓存
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);

        // 2. 获取文件信息
        Attachment attachment = attachmentService.selectAttachmentByAttachId(attachId);

        log.info("previewFile: attachment getFilePath = {}", attachment.getFilePath());
        log.info("previewFile: RuoYiConfig.getUploadPath() = {}", RuoYiConfig.getUploadPath());

        // 确保路径拼接正确
        String fullPath = RuoYiConfig.getUploadPath() + "/" + attachment.getFilePath();
        Path filePath = Paths.get(fullPath);

        if (!Files.exists(filePath)) {
            throw new ServiceException("文件不存在");
        }

        // 3. 设置响应头
        String contentType = Files.probeContentType(filePath);
        response.setContentType(contentType != null ? contentType : "application/octet-stream");
        response.setHeader("Content-Disposition", "inline; filename=\"" +
                URLEncoder.encode(attachment.getFileName(), StandardCharsets.UTF_8.name()) + "\"");

        // 4. 使用Java原生IO流传输（完全替代IOUtils）
        try (
                InputStream in = Files.newInputStream(filePath);
                OutputStream out = response.getOutputStream()
        ) {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
            out.flush();
        }
    }
}
